#!/usr/bin/env bash
set -uo pipefail

#==============================================================#
# File      :   pg-deploy
# Ctime     :   2019-03-12
# Mtime     :   2020-12-17
# Desc      :   deploy sql change to database
# Path      :   /pg/bin/pg-deploy
# Depend    :   psql
# Author    :   Vonng(fengruohang@outlook.com)
# Copyright (C) 2018-2021 Ruohang Feng
#==============================================================#

PROG_NAME="$(basename $0))"
PROG_DIR="$(cd $(dirname $0) && pwd)"

export PATH=/usr/pgsql/bin:${PATH}

#==============================================================#
#                             Usage                            #
#==============================================================#
function usage() {
	cat <<-'EOF'
		NAME
			pg-deploy   -- deploy postgres changes

		SYNOPSIS
			pg-deploy <database> <sql_path>

		DESCRIPTION
			pg-deploy will execute sql scripts and record changes

		EXAMPLES
			pg-deploy test /pg/conf/monitor.sql

	EOF
	exit 1
}

function log_debug() {
    [[ -t 2 ]] && printf "\033[0;34m[$(date "+%Y-%m-%d %H:%M:%S")][$HOSTNAME][DEBUG] $*\033[0m\n" >&2 || \
 printf "[$(date "+%Y-%m-%d %H:%M:%S")][$HOSTNAME][DEBUG] $*\n" >&2
}

function log_info() {
    [[ -t 2 ]] && printf "\033[0;32m[$(date "+%Y-%m-%d %H:%M:%S")][$HOSTNAME][INFO] $*\033[0m\n" >&2 || \
 printf "[$(date "+%Y-%m-%d %H:%M:%S")][$HOSTNAME][INFO] $*\n" >&2
}

function log_warn() {
    [[ -t 2 ]] && printf "\033[0;33m[$(date "+%Y-%m-%d %H:%M:%S")][$HOSTNAME][WARN] $*\033[0m\n" >&2 || \
 printf "[$(date "+%Y-%m-%d %H:%M:%S")][$HOSTNAME][INFO] $*\n" >&2
}

function log_error() {
    [[ -t 2 ]] && printf "\033[0;31m[$(date "+%Y-%m-%d %H:%M:%S")][$HOSTNAME][ERROR] $*\033[0m\n" >&2 || \
 printf "[$(date "+%Y-%m-%d %H:%M:%S")][$HOSTNAME][INFO] $*\n" >&2
}



#--------------------------------------------------------------#
# Name: pg-deploy
# Arg1: filepath, path to sql file to be deployed
# Arg2: database, name of target database
#--------------------------------------------------------------#
function pg-deploy() {
	local filepath=${1}
	local database=${2}

	# check sql file exists
	if [ ! -f ${filepath} ]; then
		log_error "file not exists: ${filepath}"
		return 1
	fi

    # get cluster_name from target database, also used as connectivity check
	local cluster_name=$(psql ${database} -AXtwqc "SHOW cluster_name;")
	if [[ -z "${cluster_name}" ]]; then
		log_error "fail to connect ${database}"
		return 2
	fi

	# check database is primary
    local pg_is_primary=$(psql ${database} -1AXtwqc 'SELECT pg_is_in_recovery();' 2> /dev/null)
    if [[ $? != 0 || ${pg_is_primary} == 't' ]]; then
        log_error "${database} is in recovery"
        return 3
    fi

	# build variables
    local src_filename=$(basename ${filepath})
    local change_timestamp="$(date '+%Y%m%d_%H%M%S')"
    local change_filename="${cluster_name}_${change_timestamp}_${src_filename}"
    local change_log="/pg/change/${change_filename}"

    # get sql checksum and check dupe deploy
    local src_checksum=$(md5sum ${filepath} | awk '{print $1}')
    touch /pg/change/histroy
    if (grep -q ${src_checksum} /pg/change/histroy 2> /dev/null); then
        log_warn "found exact same change in change history"
        grep ${src_checksum} /pg/change/histroy
    	# return 4
    fi

	# write original sql change content into change log, and change meta into /pg/change/history
    cat ${filepath} > ${change_log}

    # deploy start
    status="FAIL"
    log_info "deployment sql begin: psql ${database} -f ${filepath}"
    ON_ERROR_STOP=ON VERBOSITY=verbose psql ${database} -vXf ${filepath} > /pg/tmp/result

    if [[ $? == 0 ]]; then
        status="PASS"
        log_info "[PASS] deployment sql complete"
    else
        log_error "[FAIL] deployment sql failed, check ${change_log} for detail"
    fi

    # write change meta data to /pg/change/history
    local meta="${cluster_name} $(date '+%Y-%m-%d %H:%M:%S') [${status}] ${src_checksum} ${change_log}"
    log_info "${meta}"
    echo "${meta}" >> /pg/change/history

    [[ ${status} == "PASS" ]] && return 0 || return 5
}


#==============================================================#
#                             Main                             #
#==============================================================#
if [[ $(whoami) == "root" ]]; then
	log_error "deploy with dbsu"
	return 1
fi
if (( $# < 1 )); then
	usage
fi
case "$1" in
	-h | --help) usage ;;
esac

pg-deploy "$@"